package cn.miketsu.iced.reflect;

import cn.miketsu.iced.annotation.Ignore;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * 创建model对象List
 *
 * @author wangzefeng
 * @since 1.0-SNAPSHOT
 */
public class CreateBean {

    /**
     * 获取指定包名下所有类的实例
     *
     * @param packageName 包名
     * @return 指定包名下所有类的实例List
     * @throws Exception
     * @author wangzefeng
     * @since 1.1-SNAPSHOT
     */
    public static List<Object> getObjectsInPackage(String packageName) throws Exception {
        List<Object> list = new ArrayList<>();
        getClasses(packageName).forEach(aClass -> {
            try {
                if (aClass.getAnnotation(Ignore.class) == null) {
                    list.add(aClass.getDeclaredConstructor().newInstance());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        return list;
    }

    /**
     * 获取class对象的集合
     *
     * @param pack
     * @return
     * @throws Exception
     * @since 1.0-SNAPSHOT
     */
    private static Set<Class<?>> getClasses(String pack) throws Exception {
        Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
        String packageName = new String(pack);
        String packageDirName = packageName.replace('.', '/');
        Enumeration<URL> dirs;
        try {
            dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
            while (dirs.hasMoreElements()) {
                URL url = dirs.nextElement();
                String protocol = url.getProtocol();
                if ("file".equals(protocol)) {
                    String filePath = URLDecoder.decode(url.getFile(), StandardCharsets.UTF_8);
                    findClassesInPackageByFile(packageName, filePath, classes);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return classes;
    }

    /**
     * 通过文件获取class对象
     *
     * @param packageName
     * @param packagePath
     * @param classes
     * @since 1.0-SNAPSHOT
     */
    private static void findClassesInPackageByFile(String packageName, String packagePath, Set<Class<?>> classes) {
        File dir = new File(packagePath);
        if (!dir.exists() || !dir.isDirectory()) {
            return;
        }
        File[] dirfiles = dir.listFiles(file -> (file.isDirectory()) || (file.getName().endsWith(".class")));
        if (dirfiles != null) {
            for (File file : dirfiles) {
                if (file.isDirectory()) {
                    findClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), classes);
                } else {
                    String className = file.getName().substring(0, file.getName().length() - 6);
                    try {
                        classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
